package com.zhuliwei.controller;

import com.zhuliwei.constants.SystemConstants;
import com.zhuliwei.domain.ResponseResult;
import com.zhuliwei.domain.dto.MultiModelDto;
import com.zhuliwei.domain.entity.ChatContent;
import com.zhuliwei.enums.AppHttpCodeEnum;
import com.zhuliwei.exception.SystemException;
import com.zhuliwei.utils.IPUtil;
import com.zhuliwei.utils.SecurityUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.image.ImagePrompt;
import org.springframework.ai.image.ImageResponse;
import org.springframework.ai.model.Media;
import org.springframework.ai.openai.*;
import org.springframework.ai.openai.api.OpenAiAudioApi;
import org.springframework.ai.openai.api.OpenAiImageApi;
import org.springframework.ai.openai.audio.speech.SpeechPrompt;
import org.springframework.ai.openai.audio.speech.SpeechResponse;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;

import static com.zhuliwei.constants.RabbitConstants.CHAT_EXCHANGE_NAME;

/**
 * @author 朱力维
 * @time 2024/11/14 20:59
 **/
@RequestMapping("/ai")
@RestController
public class AiController {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private ChatModel chatModel;

    @Autowired
    private OpenAiImageModel openaiImageModel;

    @Autowired
    private OpenAiAudioSpeechModel openAiAudioSpeechModel;


//    报错原因 chatclient默认配置没配chatgpt模型
//    private final ChatClient chatClient;
//
//    public AiController(ChatClient.Builder chatClient) {
//        this.chatClient = chatClient.build();
//    }

    //
    @Autowired
    private ChatClient chatClient;

    @GetMapping("/chat")
    public ResponseResult generation(@RequestParam String userInput, HttpServletRequest request) {
        String answer = "";
        try {
            answer = chatClient.prompt()
                    .user(userInput)
                    .call()
                    .content();
        } catch (Exception e) {
            answer = "接口异常：" + e;
            asyncInsert(userInput, request, answer, 1, SystemConstants.CHAT_CONTENT_NORMAL);
            throw new RuntimeException();
        }
        asyncInsert(userInput, request, answer, 0,SystemConstants.CHAT_CONTENT_NORMAL);
        return ResponseResult.okResult(answer);
    }

    //多模态（图片+文件）
    @PostMapping("/multi")
    public ResponseResult multiModel(@RequestBody MultiModelDto multiModelDto, HttpServletRequest request) {
        String answer = "";
        try {
            UserMessage userMessage = new UserMessage(multiModelDto.getUserInput(),
                    new Media(MimeTypeUtils.IMAGE_PNG, multiModelDto.getImgUrl()));

            ChatResponse response = chatModel.call(new Prompt(userMessage,
                    OpenAiChatOptions.builder().withModel("gpt-4o").build()));
            answer = response.getResult().getOutput().getContent();
        } catch (Exception e) {
            answer = "多模态接口异常：" + e;
            asyncInsert(multiModelDto.getUserInput() + multiModelDto.getImgUrl(), request, answer, 1,SystemConstants.CHAT_CONTENT_MULTI);
            throw new RuntimeException();
        }
        asyncInsert(multiModelDto.getUserInput() + multiModelDto.getImgUrl(), request, answer, 0,SystemConstants.CHAT_CONTENT_MULTI);
        return ResponseResult.okResult(answer);
    }

//    @GetMapping("/chat")
//    public ResponseResult generation(String userInput, HttpServletRequest request) {
//        String answer = "";
//        try {
//            answer = chatModel.call(new Prompt(
//                    userInput,
//                    OpenAiChatOptions.builder()
//                            .withModel("gpt-4o")
//                            .build()
//            )).getResult().getOutput().getContent();
//        } catch (Exception e) {
//            answer = "普通问答接口异常：" + e;
//            asyncInsert(userInput, request, answer, 1);
//            throw new RuntimeException();
//        }
//        asyncInsert(userInput, request, answer, 0);
//        return ResponseResult.okResult(answer);
//    }

    //文生图
    @GetMapping("/image")
    public ResponseResult testImage(@RequestParam String userInput, HttpServletRequest request) {
        String answer = "";
        try {
            ImageResponse response = openaiImageModel.call(
                    new ImagePrompt(userInput,
                            OpenAiImageOptions.builder()
                                    //要使用的模型 默认：DALL_E_3模型
                                    .withModel(OpenAiImageApi.DEFAULT_IMAGE_MODEL)
                                    // 图片质量，hd表示图片更清晰
                                    .withQuality("hd")
                                    // 生成几张
                                    .withN(1)
                                    .withHeight(1024)
                                    .withWidth(1024).build())

            );
            String url = response.getResult().getOutput().getUrl();
            answer = url;
        } catch (Exception e) {
            answer = "图片生成接口异常：" + e;
            asyncInsert(userInput, request, answer, 1,SystemConstants.CHAT_CONTENT_IMAGE);
            throw new RuntimeException();
        }
        asyncInsert(userInput, request, answer, 0,SystemConstants.CHAT_CONTENT_IMAGE);
        return ResponseResult.okResult(answer);
    }

    // 文生语音
    @GetMapping("/audioDownload")
    public void downloadFile(@RequestParam String userInput, HttpServletRequest request, HttpServletResponse response) {
        // 创建一个示例的byte数组，通常这个数据来自于文件或其他来源
        OpenAiAudioSpeechOptions speechOptions = OpenAiAudioSpeechOptions.builder()
                .withResponseFormat(OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3)
                .withSpeed(1.0f)
                .withModel(OpenAiAudioApi.TtsModel.TTS_1.value)
                .build();

        SpeechPrompt speechPrompt = new SpeechPrompt(userInput, speechOptions);
        SpeechResponse speechResponse = openAiAudioSpeechModel.call(speechPrompt);

        byte[] byteArray = speechResponse.getResult().getOutput();
        // 定义一个MP3文件的模拟大小，比如1MB
//        int mp3FileSize = 1 * 1024 * 1024; // 1 MB
//        byte[] byteArray = new byte[mp3FileSize];
//
//        // 用随机数据填充数组
//        Random random = new Random();
//        random.nextBytes(byteArray);
        // 跨域后系统为了安全去掉自定义头,前端想获取自定义头需要设置Access-Control-Expose-Headers
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        // 设置响应头
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + new Date().getTime() + ".mp3");
        String answer = "";
        // 将byte数组写入响应输出流
        try (OutputStream outputStream = response.getOutputStream()) {
            outputStream.write(byteArray);
            outputStream.flush();
            answer = "语音生成成功！正在通过浏览器下载到本地。";
        } catch (Exception e) {
            answer = "语音生成接口异常：" + e;
            asyncInsert(userInput, request, answer, 1,SystemConstants.CHAT_CONTENT_AUDIO);
            throw new SystemException(AppHttpCodeEnum.AUDIO_DOWNLOAD_ERR);
        }
        asyncInsert(userInput, request, answer, 0,SystemConstants.CHAT_CONTENT_AUDIO);
    }


    /**
     * 这里的主要步骤是：
     * 创建一个临时File对象。
     * 使用MultipartFile提供的transferTo(File dest)方法将其内容写入到该文件。
     * 创建一个FileSystemResource，并传入上面生成的文件。
     * 请注意，使用临时文件时要小心资源管理，确保在不需要的时候删除临时文件以释放资源。你可以在使用后删除文件或者设置程序退出时自动删除，例如使用tempFile.deleteOnExit()。
     *
     * @param multipartFile
     * @return
     * @throws IOException
     */


    /**
     * 提问记录异步存入数据库
     *
     * @param userInput 提问内容
     * @param request
     * @param answer    回答内容
     */
    private void asyncInsert(String userInput, HttpServletRequest request, String answer, Integer status,String type) {
        ChatContent chatContent = new ChatContent();
        chatContent.setType(type);
        chatContent.setIpAddress(IPUtil.getIpAddress(request));
        chatContent.setQuestion(userInput);
        chatContent.setAnswer(answer);
        chatContent.setCreateBy(SecurityUtils.getUserId());
        chatContent.setCreateTime(new Date());
        chatContent.setStatus(status);
        rabbitTemplate.convertAndSend(CHAT_EXCHANGE_NAME, "", chatContent);
    }
}
